using System;
using System.Collections.Generic;
using System.Text;
using XLETL.Common;
using XLETL.Model;
using System.Linq;
using System.Xml.Linq;
using System.IO;

namespace XLETL.BLL
{
    	/// <summary>
	/// A business component to manage users
	/// </summary>
    public class User
    {
        /// <summary>
        /// Save User Details into the system
        /// </summary>
        public bool SaveUser(UserInfo user)
        {
            if (user == null)
            {
                throw new ArgumentNullException("Parameter \"user\" is null");
            }

            XElement users = new XElement(UserInfo.USER_COL);

            if (File.Exists(GlobalCache.USER_STORAGE_PATH))
            {
                // load all users
                XElement existingUsers = XElement.Load(GlobalCache.USER_STORAGE_PATH);

                IEnumerable<XElement> singleUser = null;
                Guid userID;

                // only update 
                if (!user.Id.Equals(Guid.Empty))
                {
                    userID = user.Id;

                    //obtain a single user
                    singleUser = (from targetUser in existingUsers.Elements(UserInfo.USER_INFO)
                                  where ((Guid)targetUser.Element(UserInfo.USER_ID)).Equals(userID)
                                  select targetUser);
                }
                else
                {
                    userID = Guid.NewGuid();
                }

                XElement newUser = new XElement(UserInfo.USER_INFO,
           new XElement(UserInfo.USER_ID, userID),
           new XElement(UserInfo.FIRST_NAME, user.FirstName),
           new XElement(UserInfo.LAST_NAME, user.LastName),
           new XElement(UserInfo.EMAIL, user.Email),
           new XElement(UserInfo.PHONE, user.Phone),
           new XElement(UserInfo.USERNAME, user.UserName),
           new XElement(UserInfo.PASSWORD, user.Password),
           new XElement(UserInfo.DATABASE_ID, user.DatabaseID)
           );

                if (singleUser != null)
                {
                    //update user, should only be 1
                    foreach (XElement xe in singleUser)
                    {
                        //xe.Remove();
                        xe.ReplaceWith(newUser);
                    }

                    existingUsers.Save(GlobalCache.USER_STORAGE_PATH);

                }
                else
                {
                    users.Add(existingUsers.Elements(UserInfo.USER_INFO));
                    users.Add(newUser);
                    users.Save(GlobalCache.USER_STORAGE_PATH);
                }

                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Search for a user based on the database id
        /// </summary>
        public List<UserInfo> GetUsers(Guid databaseId)
        {
            if (File.Exists(GlobalCache.USER_STORAGE_PATH))
            {
                XElement existingUsers = XElement.Load(GlobalCache.USER_STORAGE_PATH);

                var users = from userElement in existingUsers.Elements(UserInfo.USER_INFO)
                            let dbid = (Guid)userElement.Element(UserInfo.DATABASE_ID)
                            where dbid.Equals(databaseId)
                                select new UserInfo
                                {
                                    Id = (Guid)userElement.Element(UserInfo.USER_ID),
                                    FirstName = (string)userElement.Element(UserInfo.FIRST_NAME),
                                    LastName = (string)userElement.Element(UserInfo.LAST_NAME),
                                    Email = (string)userElement.Element(UserInfo.EMAIL),
                                    Phone = (string)userElement.Element(UserInfo.PHONE),
                                    UserName = (string)userElement.Element(UserInfo.USERNAME),
                                    Password = (string)userElement.Element(UserInfo.PASSWORD),
                                    DatabaseID = (Guid)userElement.Element(UserInfo.DATABASE_ID)
                                };
                return users.ToList<UserInfo>();
            }
            else return new List<UserInfo>();
        }

		/// <summary>
		/// Delete User from the system
		/// </summary>
		/// <param name="userId">Unique identity of user</param>
        public void DeleteUser(Guid userId)
        {
            if (userId == null)
            {
                return;
            }

            if (File.Exists(GlobalCache.USER_STORAGE_PATH))
            {
                // load all users
                XElement existingUsers = XElement.Load(GlobalCache.USER_STORAGE_PATH);

                //obtain a single company
                IEnumerable<XElement> singleUser = (from targetUser in existingUsers.Elements(UserInfo.USER_INFO)
                                                    where ((Guid)targetUser.Element(UserInfo.USER_ID)).Equals(userId)
                                                    select targetUser);
                //remove user, should only be 1
                foreach (XElement xe in singleUser)
                {
                    xe.Remove();
                }

                existingUsers.Save(GlobalCache.USER_STORAGE_PATH);
            }
        }

        /// <summary>
        /// Search for a user based on the username, password
        /// </summary>
        public UserInfo GetUser(string username, string password)
        {
            if (File.Exists(GlobalCache.USER_STORAGE_PATH))
            {
                XElement existingUsers = XElement.Load(GlobalCache.USER_STORAGE_PATH);

                var users = from userElement in existingUsers.Elements(UserInfo.USER_INFO)
                            let userName = (string)userElement.Element(UserInfo.USERNAME)
                            let pass = (string)userElement.Element(UserInfo.PASSWORD)
                            where userName.Equals(username) && pass.Equals(password)
                            select new UserInfo
                            {
                                Id = (Guid)userElement.Element(UserInfo.USER_ID),
                                FirstName = (string)userElement.Element(UserInfo.FIRST_NAME),
                                LastName = (string)userElement.Element(UserInfo.LAST_NAME),
                                Email = (string)userElement.Element(UserInfo.EMAIL),
                                Phone = (string)userElement.Element(UserInfo.PHONE),
                                UserName = (string)userElement.Element(UserInfo.USERNAME),
                                Password = (string)userElement.Element(UserInfo.PASSWORD),
                                DatabaseID = (Guid)userElement.Element(UserInfo.DATABASE_ID)
                            };
                List<UserInfo> ls = users.ToList<UserInfo>();
                if (ls.Count > 0)
                {
                    return ls[0];
                }
                else { return null; }                
            }
            else return null;
        }
   
}
}
